package com.yfunc.common.persistence.defaults;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import javax.sql.DataSource;

import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.springframework.core.io.ClassPathResource;

import com.yfunc.common.persistence.ibatis.CommandInterceptor;
import com.yfunc.common.persistence.ibatis.EntityMapper;

public class Settings {

	private Environment.Builder builder;
	private List<String> resouces;
	private Configuration configuration;
	private SqlSessionFactory sqlSessionFactory;

	public Settings() {
		this(UUID.randomUUID().toString());
	}

	public Settings(String id) {
		builder = new Environment.Builder(id);
		resouces = new ArrayList<String>();
	}

	public void dataSource(DataSource dataSource) {
		builder.dataSource(dataSource);
	}

	public void transactionFactory(TransactionFactory transactionFactory) {
		builder.transactionFactory(transactionFactory);
	}

	public void addMapperDirectory(String path) {

		ClassPathResource resource = new ClassPathResource(path);
		try {
			File file = resource.getFile();
			if (file.exists() && file.isDirectory()) {
				for (File f : file.listFiles()) {
					this.resouces.add(file.getName() + "/" + f.getName());
				}
			}
		} catch (IOException e) {
			throw new IllegalArgumentException(e);
		}

	}

	public void addMapper(String... resources) {
		for (String resource : resources) {
			this.resouces.add(resource);
		}
	}

	public Configuration getConfiguration() {
		if (configuration == null) {
			configuration = new Configuration(builder.build());
			this.initialConfiguration(configuration);
		}
		return configuration;
	}

	public SqlSessionFactory getSqlSessionFactory() {
		if (sqlSessionFactory == null) {
			Configuration configuration = getConfiguration();
			sqlSessionFactory = new SqlSessionFactoryBuilder()
					.build(configuration);
		}
		return sqlSessionFactory;
	}

	private void addMapperOfResource(String resource,
			Configuration configuration) {
		try {
			InputStream inputStream = Resources.getResourceAsStream(resource);
			XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream,
					configuration, resource, configuration.getSqlFragments());
			mapperParser.parse();
		} catch (IOException e) {
			throw new IllegalArgumentException(e);
		}
	}

	private void initialConfiguration(Configuration config) {
		config.addMapper(EntityMapper.class);
		config.addInterceptor(new CommandInterceptor());
		for (String resource : this.resouces) {
			this.addMapperOfResource(resource, config);
		}
	}
}
